#ifndef ABB_H
#define ABB_H

#include "pila.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>

/* ******************************************************************
 *                DEFINICION DE LOS TIPOS DE DATOS                  *
 * *****************************************************************/

typedef struct abb abb_t;
typedef struct abb_iter abb_iter_t;

typedef int (*abb_comparar_clave_t) (const char *, const char *);
typedef void (*abb_destruir_dato_t) (void *);

/* ******************************************************************
 *                    	 PRIMITIVAS DEL ABB  						*
 * *****************************************************************/

// Crea un ABB. Si se recibe la función destruir_dato por parámetro,
// para cada uno de los elementos del ABB, llama a destruir_dato.
// Si se recibe comparar_clave (cmp), se la utiliza para los elementos dos a dos.
// Pre: destruir_dato es una función capaz de destruir los datos del árbol
// y cmp de comparar dos claves, o NULL en caso de no utilizarlas.
// Post: devuelve un nuevo ABB vacío.
abb_t* abb_crear(abb_comparar_clave_t cmp, abb_destruir_dato_t destruir_dato);

// Destruye el ABB.
// Pre: el ABB fue creado.
// Post: se eliminaron todos los elementos del ABB.
void abb_destruir(abb_t *arbol);

// Devuelve la cantidad de elementos existentes en el ABB.
// Pre: el ABB fue creado.
// Post: se devolvió la cantidad de elementos del ABB.
// En caso de estar vacío, lógicamente, la función devuelve 0 (cero).
size_t abb_cantidad(abb_t *arbol);

// Agrega un nuevo elemento al ABB. Devuelve falso en caso de error.
// Pre: el ABB fue creado.
// Post: se agregó un nuevo elemento al ABB.
bool abb_guardar(abb_t *arbol, const char *clave, void *dato);

// Obtiene el valor correspondiente a la clave pasada al ABB.
// Devuelve NULL en caso de no existir.
// Pre: el ABB fue creado.
// Post: en caso de existir, se devolvió el valor solicitado
// sin removerlo del ABB.
void* abb_obtener(const abb_t *arbol, const char *clave);

// Devuelve verdadero si la clave contiene algún valor adjunto,
// falso en caso contrario.
// Pre: el ABB fue creado.
// Post: se informó el 'estado' de la clave.
bool abb_pertenece(const abb_t *arbol, const char *clave);

// Saca el elemento correspondiente a la clave pasada.
// Devuelve NULL en caso de no existir.
// Pre: el ABB fue creado.
// Post: en caso de existir, se devolvió el valor solicitado habiéndolo
// removido del ABB previamente. El ABB contiene un elemento menos y fue 
// reordenado.
void* abb_borrar(abb_t *arbol, const char *clave);

// Itera internamente por el ABB 'in order', es decir, izq-raíz-der.
// Si se recibe 'funcion', ésta será aplicada a cada elemento.
// El puntero a void 'extra' será pasado como último parámetro de 'funcion'.
// Pre: el ABB fue creado.
// Post: se iteró por todo el ABB 'in order' aplicando 'funcion' a cada elemento.
void abb_in_order(abb_t *arbol, bool funcion(const char *, void *, void *), void *extra);

/* *****************************************************************
 *                    PRIMITIVAS DEL ITERADOR                      *
 * *****************************************************************/

// Crea un iterador.
// Pre: el ABB fue creado.
// Post: se creó un iterador que apunta hacia la primer raíz del ABB.
abb_iter_t* abb_iter_in_crear(const abb_t *arbol);

// El iterador avanza a la siguiente raíz u hoja. Si el ABB
// no tiene elementos o el iterador se encuentra al final de él, devuelve falso.
// Pre: el ABB y el iterador fueron creados.
// Post: el iterador avanzó a la siguiente posición (de ser posible).
bool abb_iter_in_avanzar(abb_iter_t *iter);

// Da la clave de la posición donde se encuentra el iterador.
// Pre: el ABB y el iterador fueron creados.
// Post: se devolvió la clave de la posición donde se encuentra el iterador.
const char* abb_iter_in_ver_actual(const abb_iter_t *iter);

// Devuelve verdadero si el iterador se encuentra al final del ABB,
// falso en caso contrario.
// Pre: el ABB y el iterador fueron creados.
bool abb_iter_in_al_final(const abb_iter_t *iter);

// Destruye el iterador.
// Pre: el iterador fue creado.
// Post: se destruyó el iterador.
void abb_iter_in_destruir(abb_iter_t* iter);


#endif //ABB_H
